package com.t.bricks.bussiness.component.lucene;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

import com.t.bricks.bussiness.util.lucene.LuceneFactory;
import com.t.bricks.model.Log;
import com.t.bricks.model.MsgEmity;
import com.t.bricks.model.OrderInfo;
import com.t.bricks.model.OrderInfoList;
import com.t.bricks.model.Page;
import com.t.bricks.utils.function.json.JacksonShell;
import com.t.bricks.utils.spring.ModuleUtil;

/**
 * 搜索引擎切面子类,专门处理分页查询数据时的关联操作
 */
@Component
@Aspect
public class LuceneAspectFindByPage extends LuceneAspectBase {

	/**
	 * 搜索引擎进行AOP操作findByPage时,是否仅当参数like有值时才接入
	 */
	@Value("${app.lucene.aop.fing.like.only:true}")
	private boolean isOnlyLike ;

	/**
	 * 是否允许搜索引擎进行AOP操作findByPage
	 */
	@Value("${app.lucene.aop.fing.can:true}")
	private boolean isCanAopFindByPage;

	/**
	 * 定义切入点，切入点为'com.t.bricks.bussiness.db.dao.*.impl.*DaoImpl.findByPage(Page, ?, String, ?)'下的所有函数,
	 */
	@Pointcut(value = "execution(com.t.bricks.model.MsgEmity com.t.bricks.bussiness.db.dao.*.impl..*DaoImpl.findByPage(com.t.bricks.model.Page,com.t.bricks.model.OrderInfoList,String,*))"
			+ " || execution(com.t.bricks.model.MsgEmity com.t.bricks.bussiness.db.dao.common.impl.CommonDaoImpl.findByPage(com.t.bricks.model.Page,com.t.bricks.model.OrderInfoList,String,Object,boolean,Class))")
	//@Pointcut(value = "execution(* com.t.bricks.bussiness.db.dao.followup.impl..FollowUpDaoImpl.*(..))")
	@Override
	public void doLuceneAspect() {
	}

    /**
     * 环绕通知
     * @param joinPoint
     * @return
     * @throws Throwable
     */
	@Around("doLuceneAspect()")
	@Override
	public Object doAround(ProceedingJoinPoint joinPoint) throws Throwable {
		if (!isCanAop) {
			return joinPoint.proceed();//执行原切面中的预定方法后返回内容
		}
		
		if (!isCanAopFindByPage) {
			return joinPoint.proceed();//执行原切面中的预定方法后返回内容
		}
		
		Object[] objs = joinPoint.getArgs();
		if (isOnlyLike) {//配置中要求仅对使用了模糊查询时才进行搜索引擎接入
			String sLikeStr = (String)objs[2];
			if (null == sLikeStr || "".equals(sLikeStr.trim())) {
				return joinPoint.proceed();//执行原切面中的预定方法后返回内容
			}
		}
		
		return findByPage(joinPoint);//取代之前的查询方法
	}
	
	/**
	 * 查询多个字段
	 * @param joinPoint
	 * @return
	 * @throws Throwable 
	 */
	public Object findByPage(ProceedingJoinPoint joinPoint) throws Throwable {
		MsgEmity me = crateLuceneCore(joinPoint, sLuceneIndexPath);//建立搜索库
		if (!me.isSuccess()) {
			return joinPoint.proceed();//执行原切面中的预定方法后返回内容
		}
		
		//被切面的函数：findByPage(Page page, OrderInfoList orders, String sLikeStr, ConditionFollowUp condition)
		Object[] objs = joinPoint.getArgs();
		if (null == objs || objs.length < 4) {
			Log.error("搜索引擎查询数据失败，切面的参数数量不足4个!");
			return joinPoint.proceed();//执行原切面中的预定方法后返回内容
		}

		Page page = null;
		try {//有转换失败的风险
			page = (Page)objs[0];
		} catch (Exception e) {
			Log.error("搜索引擎查询数据失败，切面的参数转换失败，可能是类型不匹配!异常信息:", e.getMessage());
			return joinPoint.proceed();//执行原切面中的预定方法后返回内容
		}

		boolean onlyCreator = false;
		String beanName = getDaoBeanName(joinPoint);
		if ("commonDaoImpl".equals(beanName)) {
			onlyCreator = (boolean)objs[4];
		}
		
		Map<String, Boolean> sortMap = getSortMap(objs);//获取排序信息
		Map<String, List<String>> condition = getCondition(objs, onlyCreator);//获取查询条件信息
		
		if (null == condition) {
			String sLikeStr = (String)objs[2];
			me = LuceneFactory.search(sLikeStr, sortMap, page, Object.class,
					getCore(joinPoint, sLuceneIndexPath));
		} else {
			me = LuceneFactory.search(condition.get("fields"),
					condition.get("keys"),
					condition.get("rels"),
					sortMap,
					page,
					Object.class,
					getCore(joinPoint, sLuceneIndexPath));
		}
				
		if (!me.isSuccess()) {
			Log.error("搜索引擎查询数据失败!");
			return joinPoint.proceed();//执行原切面中的预定方法后返回内容
		}
		
		return me;
	}
	
//	/**
//	 * 查询多个字段
//	 * @param joinPoint
//	 * @param msgEmity
//	 * @return
//	 */
//	public MsgEmity findByPage(ProceedingJoinPoint joinPoint, MsgEmity msgEmity) {
//		MsgEmity me = crateLuceneCore(joinPoint);//建立搜索库
//		if (!me.isSuccess()) {
//			return msgEmity;
//		}
//		
//		Page dbPage = msgEmity.getData();//从数据库得到的结果数据
//		if (dbPage.getRecordList().size() >= dbPage.getPageSize()) {
//			return msgEmity;//从当前数据库已经查找到足量的数据，不需要再从搜索引擎获取
//		}
//		
//		Object[] objs = joinPoint.getArgs();
//		if (null == objs || objs.length < 4) {
//			Log.error("搜索引擎查询数据失败，切面的参数数量不足4个!");
//			return msgEmity;//原数据路返回
//		}
//		
//		String sLikeStr = (String)objs[2];
//		
//		Class<?> clazz = getGenericClass(msgEmity);
//		Page page = new Page(dbPage.getPageCurrent(), dbPage.getPageSize());
//		me = LuceneFactory.search(sLikeStr, page, clazz, getCore(joinPoint));
//
//		if (!me.isSuccess()) {
//			Log.error("搜索引擎查询数据失败!");
//			return msgEmity;//原数据路返回
//		}
//		
//		List<?> list = page.getRecordList();
//		for (Object object : list) {
//			dbPage.getRecordList().add(object);
//			if (dbPage.getRecordList().size() >= dbPage.getPageSize()) {
//				break;
//			}
//		}
//		
//		return msgEmity;//满载而归
//	}

//	/**
//	 * 查询多个字段
//	 * @param keys 关键字 {"字段1关键字", "字段2关键字"}
//	 * @param page 分页信息
//	 * @param clazz 返回的数据类型
//	 * @return
//	 */
//	public MsgEmity search(List<String> keys, Page page) {
//		return LuceneFactory.search(keys, page, getGenericClass(msgEmity), getCore(joinPoint));
//	}
//
//	/**
//	 * 查询单个字段
//	 * @param field 待查字段
//	 * @param key 关键字(只有一个),如果含有空格,则按or条件处理
//	 * @param page 分页信息
//	 * @param clazz 返回的数据类型
//	 * @return
//	 */
//	public MsgEmity search(String field, String key, Page page) {
//		return LuceneFactory.search(field, key, page, getGenericClass(msgEmity), getCore(joinPoint));
//	}
//
//	/**
//	 * 查询contents字段
//	 * @param key 关键字(只有一个),如果含有空格,则按or条件处理
//	 * @param page 分页信息
//	 * @return
//	 */
//	public MsgEmity search(String key, Page page) {
//		return LuceneFactory.search(key, page, getGenericClass(msgEmity), getCore(joinPoint));
//	}
	
	/**
	 * 获取排序信息
	 * @param objs
	 * @return
	 */
	private Map<String, Boolean> getSortMap(Object[] objs) {
		if (null == objs || objs.length < 2 || null == objs[1]) {
			return null;
		}

		OrderInfoList orders = null;
		try {
			orders = (OrderInfoList)objs[1];
		} catch (Exception e) {
			Log.error("搜索引擎查询数据中转换排序信息失败，可能是类型不匹配!异常信息:", e.getMessage());
			return null;
		}
		
		Map<String, Boolean> result = null;		
		
		if (null != orders && orders.size() > 0) {
			result = new LinkedHashMap<String, Boolean>();
			for (OrderInfo orderInfo : orders.getOrderInfoList()) {
				String sOrderField = orderInfo.getsOrderField();
				int iSt = sOrderField.lastIndexOf(".");
				if (iSt > -1) {
					sOrderField = sOrderField.substring(iSt +1, sOrderField.length());
				}
				
				boolean bl = "DESC".equals(orderInfo.getsDirection());//(升序ASC 降序DESC)
				result.put(sOrderField, bl);
			}
		}
		
		return result;
	}
	
	/**
	 * 获取精确字段查询信息
	 * @param objs
	 * @param onlyCreator
	 * @return
	 */
	private Map<String, List<String>> getCondition(Object[] objs, boolean onlyCreator) {
		if (null == objs || objs.length < 4 || null == objs[3]) {
			if (onlyCreator) {
				Map<String, List<String>> result = new HashMap<String, List<String>>(1);
				result.put("fields", Arrays.asList("sCreator"));
				result.put("rels", Arrays.asList("and"));
				result.put("keys", Arrays.asList(ModuleUtil.currentLoginUserId()));
				
				return result;
			}
			
			return null;
		}
		
		List<String> fields = new ArrayList<String>();
		List<String> keys = new ArrayList<String>();
		List<String> rels = new ArrayList<String>();

		//--无视具体类型,直接将其转换成json遍历其kv信息--//
		Map<String, Object> condition = JacksonShell.toJavaObject(objs[3], Map.class);
		//JSONObject condition = (JSONObject) JSON.toJSON(objs[3]);
		for (Map.Entry<String, Object> entry : condition.entrySet()) {
			if (null == entry.getValue() || "null".equalsIgnoreCase(entry.getValue().toString())
					|| "".equals(entry.getValue().toString())) {
				continue;
			}
			
			fields.add(entry.getKey());
			rels.add("and");
			keys.add(entry.getValue().toString());
        }
		
		//--仅创建者可见--//
		if (onlyCreator) {
			fields.add("sCreator");
			rels.add("and");
			keys.add(ModuleUtil.currentLoginUserId());
		}
		
		if (fields.size() < 1) {
			return null;
		}
		
		//--如果进行了全文检索条件,则必须加上,并且条件关系为'and'--//
		String sLikeStr = (String)objs[2];
		if (sLikeStr != null && !"".equals(sLikeStr.trim())) {
			fields.add("contents");//全文检索字段
			rels.add("and");
			keys.add(sLikeStr.trim());
		}
		
		Map<String, List<String>> result = new HashMap<String, List<String>>();
		result.put("fields", fields);
		result.put("rels", rels);
		result.put("keys", keys);
		
		return result;
	}
	
}
